﻿/* 
 * Copyright (c) 2008 Intel Corporation
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * -- Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * -- Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * -- Neither the name of the Intel Corporation nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE INTEL OR ITS
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

using System;
using System.Collections.Generic;

namespace WorldServer
{
    public class Service
    {
        public Uri Identifier;
        public Uri XrdDocument;
        public Uri SeedCapability;
        public Uri OAuthRequestToken;
        public Uri OAuthAuthorizeToken;
        public Uri OAuthGetAccessToken;
        public bool IsTrusted;
        public bool CanOverride;
        public Dictionary<Uri, Uri> Capabilities;

        public Service(Uri identifier, Uri xrdDocument, Uri seedCapability, Uri oAuthRequestToken, Uri oAuthAuthorizeToken, Uri oAuthGetAccessToken,
            bool isTrusted, bool canOverride, Dictionary<Uri, Uri> capabilities)
        {
            Identifier = identifier;
            XrdDocument = xrdDocument;
            SeedCapability = seedCapability;
            OAuthRequestToken = oAuthRequestToken;
            OAuthAuthorizeToken = oAuthAuthorizeToken;
            OAuthGetAccessToken = oAuthGetAccessToken;
            IsTrusted = isTrusted;
            CanOverride = canOverride;
            this.Capabilities = new Dictionary<Uri, Uri>(capabilities);
        }

        public Service(Uri identifier, Uri xrdDocument, Uri seedCapability, Uri oAuthRequestToken, Uri oAuthAuthorizeToken, Uri oAuthGetAccessToken,
            bool isTrusted, bool canOverride)
            : this(identifier, xrdDocument, seedCapability, oAuthRequestToken, oAuthAuthorizeToken, oAuthGetAccessToken, isTrusted, canOverride, new Dictionary<Uri, Uri>())
        {
        }

        public Service(Service service)
        {
            Identifier = service.Identifier;
            XrdDocument = service.XrdDocument;
            SeedCapability = service.SeedCapability;
            OAuthRequestToken = service.OAuthRequestToken;
            OAuthAuthorizeToken = service.OAuthAuthorizeToken;
            OAuthGetAccessToken = service.OAuthGetAccessToken;
            IsTrusted = service.IsTrusted;
            CanOverride = service.CanOverride;
            this.Capabilities = new Dictionary<Uri, Uri>(service.Capabilities);
        }

        public Uri[] GetUnassociatedCapabilities()
        {
            List<Uri> unassociated = new List<Uri>();

            foreach (KeyValuePair<Uri, Uri> cap in Capabilities)
            {
                if (cap.Value == null)
                    unassociated.Add(cap.Key);
            }

            return unassociated.ToArray();
        }

        public bool TryGetCapability(Uri capIdentifier, out Uri location)
        {
            if (Capabilities.TryGetValue(capIdentifier, out location) && location != null)
                return true;
            return false;
        }

        public override string ToString()
        {
            bool first = true;
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            foreach (KeyValuePair<Uri, Uri> entry in Capabilities)
            {
                if (first)
                    first = false;
                else
                    sb.Append(',');

                sb.Append(entry.Key.Segments[entry.Key.Segments.Length - 1]);

                if (entry.Value != null)
                    sb.Append(":" + entry.Value);
            }

            bool trusted = IsTrusted;
            string location;
            if (trusted)
                location = SeedCapability.ToString();
            else
                location = (OAuthGetAccessToken != null) ? OAuthGetAccessToken.ToString() : "null";

            return String.Format("{0} (Location: {1}, {2} {3}, Capabilities: {4})",
                Identifier,
                location,
                trusted ? "Trusted" : "Untrusted",
                CanOverride ? "CanOverride" : "NoOverride",
                sb.ToString());
        }
    }

    public class ServiceCollection : Dictionary<Uri, Service>
    {
        public ServiceCollection()
        {
        }

        public ServiceCollection(IEnumerable<Service> services)
        {
            foreach (Service service in services)
                this[service.Identifier] = service;
        }

        public Dictionary<Uri, Dictionary<Uri, Uri>> ToMessageDictionary()
        {
            Dictionary<Uri, Dictionary<Uri, Uri>> d = new Dictionary<Uri, Dictionary<Uri, Uri>>(this.Count);

            foreach (KeyValuePair<Uri, Service> serviceEntry in this)
                d.Add(serviceEntry.Key, serviceEntry.Value.Capabilities);

            return d;
        }
    }
}
